#include "gdt.h"

#include "vga_text.h"

typedef struct _gdtr
{
	uint16_t limit;
	uint32_t base;
}gdtr;


static gdtr _gdtRegister;
static gdt_descriptor _gdt[MAX_DESCRIPTORS];

void i86_set_gdtdescriptor(uint32_t gdtNo,uint64_t limit,uint64_t base,uint8_t flags,uint8_t grand)
{
	if(gdtNo > MAX_DESCRIPTORS)
		return;

	memset(&_gdt[gdtNo],0,sizeof(gdt_descriptor));

	_gdt[gdtNo].limitLo = (uint16_t)(limit & 0xffff);
	_gdt[gdtNo].baseLo = (uint16_t)(base & 0xffff);
	_gdt[gdtNo].baseMid = (uint8_t)((base >> 16) & 0xff);
	_gdt[gdtNo].flags = flags;
	_gdt[gdtNo].grand = (uint8_t)((limit >> 16) & 0x0f);
	_gdt[gdtNo].grand |= (uint8_t)(grand & 0xf0);
	_gdt[gdtNo].baseHi = (uint8_t)((base >> 24) & 0xff);

	//vga_text_mode_printk("gdt No.:%d\n value low:%b\n value high:%b\n",gdtNo,*(uint32_t *)&_gdt[gdtNo],*((uint32_t *)&_gdt[gdtNo] + 1));
}

void i86_gdt_install()
{
	__asm
	{
		lgdt [_gdtRegister]
	}
}

gdt_descriptor_ptr i86_get_gdtdescriptor(uint32_t gdtNo)
{
	if(gdtNo > MAX_DESCRIPTORS)
		return 0;

	return &_gdt[gdtNo];
}

void i86_gdt_initialize()
{
	_gdtRegister.base = (uint32_t)&_gdt[0];
	_gdtRegister.limit = (sizeof(gdt_descriptor) * MAX_DESCRIPTORS) - 1;

	i86_set_gdtdescriptor(0,0,0,0,0);

	i86_set_gdtdescriptor(1,0xffffffff,0,I86_GDT_DESC_READWRITE|I86_GDT_DESC_EXEC_CODE|I86_GDT_DESC_CODEDATA|I86_GDT_DESC_MEMORY,
		I86_GDT_GRAND_4K | I86_GDT_GRAND_32BIT | I86_GDT_GRAND_LIMITHI_MASK);

	i86_set_gdtdescriptor(2,0xffffffff,0,I86_GDT_DESC_READWRITE|I86_GDT_DESC_CODEDATA|I86_GDT_DESC_MEMORY,
		I86_GDT_GRAND_4K | I86_GDT_GRAND_32BIT | I86_GDT_GRAND_LIMITHI_MASK);

	i86_gdt_install();
}